# -*- coding: utf-8 -*-
import os
import uuid
import json
from typing import List, Dict

from loguru import logger
from fastapi import Request, Form, File, BackgroundTasks
from pydantic import BaseModel
from sse_starlette import EventSourceResponse

from configs import UPLOAD_CLAUSE_FILE_DIR
from document_loader.clause_loader import ClauseLoader
from schemas.response_entity import JsonModel
from db.repository.clause import \
    db_create_clause_file, db_get_clause_file_by_filename, db_get_clause_file_by_fileId, db_update_clause_file_delete_state,\
    db_get_all_clause_files, db_get_clause_files_by_userId, db_get_comp_his_by_filter,\
    db_get_standards_by_fileId, db_get_standards_by_filter, db_update_clause_file_parse_state,\
    db_delete_clause_compare_his_by_id, db_get_clause_compare_his_by_id
from utils.file_utils import write_2_file
from utils.hash_utils import cal_md5
from utils.redis_utils import redis_pool

from .utils import compare_clauses_with_standard, iter_chat


class DeleteHisEntity(BaseModel):
    token: str
    his_id: uuid.UUID


class CompareEntity(BaseModel):
    token: str
    file_id: uuid.UUID
    stand_ids: List[uuid.UUID]


async def list_upload_clause(request: Request, token: str):
    user = request.state.user
    if user is None:
        return JsonModel(code=401, data=None, msg="用户token非法").to_response()

    if user.check_superman_role():
        clauses = db_get_all_clause_files(clause_type=1)
    else:
        clauses = db_get_clause_files_by_userId(user.id, clause_type=1)

    clauses = [i.to_json() for i in clauses]
    return JsonModel(code=200, data=clauses, msg=f"success").to_response()


async def list_compare_history(request: Request, token: str, page: int = 1, size: int = 100):
    user = request.state.user
    if user is None:
        return JsonModel(code=401, data=None, msg="用户token非法").to_response()

    total, clause_comp_history = db_get_comp_his_by_filter(user, page, size)
    data = {
        "total": total,
        "page": page,
        "size": size,
        "histories": [i.to_json() for i in clause_comp_history]
    }
    return JsonModel(code=200, data=data, msg=f"success").to_response()


# 上传要对比的条款，在后台进行对比
async def upload_compare_clause(
        background_tasks: BackgroundTasks,
        request: Request,
        file=File(None),
        stand_ids: List[uuid.UUID] = Form(None),
        token: str = Form()
):
    user = request.state.user
    if user is None:
        return JsonModel(code=401, data=None, msg="用户token非法").to_response()

    # if not user.check_admin_role():
    #     return JsonModel(code=401, data=None, msg=f"用户无权限").to_response()

    # if not user.check_permission("clause"):
    #     return JsonModel(code=402, data=None, msg=f"用户无操作权限").to_response()

    if isinstance(stand_ids, str):
        try:
            standard_clause_file_id_list = json.loads(stand_ids)
        except Exception as e:
            try:
                import ast
                standard_clause_file_id_list = ast.literal_eval(stand_ids)
            except Exception as e:
                standard_clause_file_id_list = None
    else:
        standard_clause_file_id_list = [i for i in stand_ids]

    if not standard_clause_file_id_list:
        return JsonModel(code=400, data=None, msg=f"标准条款id解析失败").to_response()

    file_content = await file.read()

    # 计算文件的 MD5 值
    file_origin_name, file_suffix = file.filename.rsplit('.', 1)
    file_name = cal_md5(file_content) + "." + file_suffix
    file_obj = db_get_clause_file_by_filename(user.id, file_name, clause_type=1)

    file_path = os.path.join(UPLOAD_CLAUSE_FILE_DIR, file_name)
    write_2_file(file_path, file_content)

    if file_obj:  # 逻辑删除时，更新
        file_obj = db_update_clause_file_delete_state(file_obj.id, delete=False)
    else:
        file_obj = db_create_clause_file(user_id=user.id, file_name=file_name, origin_name=file.filename, location=file_path,
                                    file_type=file.filename.split('.')[-1], file_size=file.size, clause_type=1)

    standard_clauses: List[Dict] = []
    for standard_clause_file_id in standard_clause_file_id_list:
        if not isinstance(standard_clause_file_id, uuid.UUID):
            standard_clause_file_id = uuid.UUID(standard_clause_file_id)  # noqa
        if user.check_superman_role():
            clauses = db_get_standards_by_fileId(standard_clause_file_id)
        else:
            clauses = db_get_standards_by_filter(user.id, standard_clause_file_id)

        for clause in clauses:
            clause_info = {"id": str(clause.id), "法规条款": clause.clause_number,
                           "人工优化过的内容": clause.artificial_text}
            standard_clauses.append(clause_info)

    clause_loader = ClauseLoader()
    parsed_docx: List[str] = clause_loader.parse_file_2_paragraph(file_path)

    background_tasks.add_task(compare_clauses_with_standard, standard_clauses, parsed_docx, file_obj, user.id)
    return JsonModel(code=200, data={"id": str(file_obj.id)}, msg=f"提交解析任务:{file.filename}成功").to_response()


# 获取后台对比条款的对比进度
def get_task_progress(request: Request, token: str, file_id: uuid.UUID):
    user = request.state.user
    if user is None:
        return JsonModel(code=401, data=None, msg="用户token非法").to_response()

    file_obj = db_get_clause_file_by_fileId(file_id, clause_type=1)
    if file_obj is None:
        return JsonModel(code=400, data=None, msg=f"新条款不存在,请更换新条款").to_response()

    # if file_obj.status == 1:  # 已经解析成功
    #     return JsonModel(code=200, data={"file_id": str(file_id), "progress": 100}, msg=f"success").to_response()

    # example: res = {"total": 20, "processed": 10, "parsed_docx": [str,...], "results": [str,...]}
    res = redis_pool.hgetall(str(file_id))
    processed = res.get("processed", None)
    total = res.get("total", None)
    if total is None:
        return JsonModel(code=400, data=None, msg=f"解析任务不存在").to_response()

    if processed is None:
        return JsonModel(code=200, data={"file_id": str(file_id), "progress": 0}, msg=f"正在解析请稍候").to_response()

    progress = int(int(processed) / int(total) * 100)
    if progress == 100:
        status = db_update_clause_file_parse_state(file_id)
    return JsonModel(code=200, data={"file_id": str(file_id), "progress": progress}, msg=f"success").to_response()


async def compare_clause(request: Request, payload: CompareEntity):
    user = request.state.user
    if user is None:
        return JsonModel(code=401, data=None, msg="用户token非法").to_response()

    file_obj = db_get_clause_file_by_fileId(payload.file_id, clause_type=1)
    if file_obj is None:
        return JsonModel(code=400, data=None, msg=f"新条款不存在,请更换新条款").to_response()

    res = redis_pool.hgetall(str(payload.file_id))
    enterprise_doc: List[str] = json.loads(res.get("parsed_docx", "[]"))
    comparison_results: List[Dict] = json.loads(res.get("results", "[]"))

    return EventSourceResponse(iter_chat(file_obj, comparison_results, enterprise_doc, user.id))


# 删除条款对比历史
async def delete_clause_compare_history(request: Request, payload: DeleteHisEntity):
    user = request.state.user
    if user is None:
        return JsonModel(code=401, data=None, msg=f"用户token 非法").to_response()

    if not user.check_admin_role():
        return JsonModel(code=401, data=None, msg=f"用户无权限").to_response()

    if user.check_superman_role():
        clause_history = db_get_clause_compare_his_by_id(payload.his_id)
    else:
        clause_history = db_get_clause_compare_his_by_id(payload.his_id, user.id)

    if clause_history is None:
        return JsonModel(code=400, data=None, msg=f"对比历史不存在,请更换").to_response()
    db_delete_clause_compare_his_by_id(clause_history.id)
    return JsonModel(code=200, data=None, msg=f"删除对比历史成功").to_response()

